/*
* Tiled Map Editor, (c) 2004-2006
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* Adam Turk <aturk@biggeruniverse.com> Bjorn Lindeijer <bjorn@lindeijer.nl>
*/
package de.yaams.extensions.basemap.tiled.mapeditor.dialogs;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.Properties;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableCellEditor;
import de.yaams.extensions.basemap.tiled.core.MapLayer;
import de.yaams.extensions.basemap.tiled.core.Tile;
import de.yaams.extensions.basemap.tiled.core.TileLayer;
import de.yaams.extensions.basemap.tiled.mapeditor.MapEditor;
import de.yaams.extensions.basemap.tiled.mapeditor.Resources;
import de.yaams.extensions.basemap.tiled.mapeditor.selection.SelectionLayer;
import de.yaams.extensions.basemap.tiled.mapeditor.util.PropertiesTableModel;
import de.yaams.extensions.basemap.tiled.mapeditor.widget.VerticalStaticJPanel;
import de.yaams.maker.programm.YaFrame;
/**
* @version $Id$
*/
public class TileInstancePropertiesDialog extends JDialog implements TableModelListener {
/**
*
*/
private static final long serialVersionUID = -8243150934312328656L;
private JTable propertiesTable;
private PropertiesTableModel tableModel = new PropertiesTableModel();
private static final String DIALOG_TITLE = "Tile Properties"; // todo:
// Resource
// this
private static final String APPLY_BUTTON = Resources.getString("general.button.apply");
private static final String APPLY_TOOLTIP = "Apply properties to selected tiles"; // todo:
// Resource
// this
private static final String DELETE_BUTTON = Resources.getString("general.button.delete");
private final MapEditor editor;
/** Holds all currently selected Properties. */
private final LinkedList<Point> propertiesCoordinates = new LinkedList<Point>();
private final Properties mergedProperties = new Properties();
public TileInstancePropertiesDialog(MapEditor editor) {
super(YaFrame.get(), DIALOG_TITLE, false);
this.editor = editor;
tableModel.addTableModelListener(this);
init();
pack();
setLocationRelativeTo(getOwner());
}
private Properties getPropertiesAt(Point p) {
MapLayer ml = editor.getCurrentLayer();
if (!(ml instanceof TileLayer)) {
return null;
}
return ((TileLayer) ml).getTileInstancePropertiesAt(p.x, p.y);
}
private void setPropertiesAt(Point point, Properties properties) {
MapLayer ml = editor.getCurrentLayer();
if (!(ml instanceof TileLayer)) {
return;
}
((TileLayer) ml).setTileInstancePropertiesAt(point.x, point.y, properties);
}
private void init() {
propertiesTable = new JTable(tableModel);
JScrollPane propScrollPane = new JScrollPane(propertiesTable);
propScrollPane.setPreferredSize(new Dimension(200, 150));
JButton applyButton = new JButton(APPLY_BUTTON);
applyButton.setToolTipText(APPLY_TOOLTIP);
JButton deleteButton = new JButton(Resources.getIcon("gnome-delete.png"));
deleteButton.setToolTipText(DELETE_BUTTON);
JPanel user = new VerticalStaticJPanel();
user.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0));
user.setLayout(new BoxLayout(user, BoxLayout.X_AXIS));
user.add(Box.createGlue());
user.add(Box.createRigidArea(new Dimension(5, 0)));
user.add(deleteButton);
JPanel buttons = new VerticalStaticJPanel();
buttons.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0));
buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS));
buttons.add(Box.createGlue());
buttons.add(applyButton);
JPanel mainPanel = new JPanel();
mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
mainPanel.add(propScrollPane);
mainPanel.add(user);
mainPanel.add(buttons);
getContentPane().add(mainPanel);
getRootPane().setDefaultButton(applyButton);
// create actionlisteners
applyButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
buildPropertiesAndApply();
}
});
deleteButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
deleteSelected();
}
});
}
public void setSelection(SelectionLayer selection) {
// Start off fresh...
// Properties mergedProperties = new Properties();
mergedProperties.clear();
propertiesCoordinates.clear();
// Get all properties of all selected tiles...
MapLayer ml = editor.getCurrentLayer();
if (ml instanceof TileLayer) {
TileLayer tl = (TileLayer) ml;
Rectangle r = selection.getSelectedAreaBounds();
int maxJ = (int) (r.getY() + r.getHeight());
int maxI = (int) (r.getX() + r.getWidth());
// todo: BL - Why are tiles checked on null? Surely whether a tile
// todo: is null or not has nothing to do with whether you can place
// todo: a property as a certain location?
for (int j = (int) r.getY(); j < maxJ; j++) {
for (int i = (int) r.getX(); i < maxI; i++) {
Tile t = selection.getTileAt(i, j);
if (t != null) {
propertiesCoordinates.add(new Point(i, j));
}
}
}
if (!propertiesCoordinates.isEmpty()) {
// Start with properties of first tile instance
Point point = propertiesCoordinates.get(0);
Properties p = tl.getTileInstancePropertiesAt(point.x, point.y);
if (p != null) {
mergedProperties.putAll(p);
for (int i = 1; i < propertiesCoordinates.size(); i++) {
// Merge the other properties...
point = propertiesCoordinates.get(i);
p = tl.getTileInstancePropertiesAt(point.x, point.y);
if (p != null) {
for (Enumeration<?> e = mergedProperties.keys(); e.hasMoreElements();) {
// We only care for properties that are already
// "known"...
String key = (String) e.nextElement();
String val = mergedProperties.getProperty(key);
String mval = p.getProperty(key);
if (mval == null) {
// Drop non-common properties
mergedProperties.remove(key);
} else if (!mval.equals(val)) {
// Hide non-common values
mergedProperties.setProperty(key, "?");
}
}
} else {
mergedProperties.clear();
break;
}
}
}
}
}
tableModel.setProperties(mergedProperties);
}
private void buildPropertiesAndApply() {
// Make sure there is no active cell editor anymore
TableCellEditor cellEditor = propertiesTable.getCellEditor();
if (cellEditor != null) {
cellEditor.stopCellEditing();
}
// Apply possibly changed properties.
applyPropertiesToTiles();
}
private void deleteFromSelectedTiles(String key) {
for (Point point : propertiesCoordinates) {
Properties p = getPropertiesAt(point);
if (p != null) {
p.remove(key);
}
}
}
private void deleteSelected() {
int total = propertiesTable.getSelectedRowCount();
Object[] keys = new Object[total];
int[] selRows = propertiesTable.getSelectedRows();
for (int i = 0; i < total; i++) {
keys[i] = propertiesTable.getValueAt(selRows[i], 0);
}
for (int i = 0; i < total; i++) {
if (keys[i] != null) {
tableModel.remove(keys[i]);
deleteFromSelectedTiles((String) keys[i]);
}
}
}
private void applyPropertiesToTiles() {
Properties properties = tableModel.getProperties();
// First delete all Properties that were previously selected
for (Point point : propertiesCoordinates) {
Properties tp = getPropertiesAt(point);
if (tp != null) {
for (Enumeration<?> e = mergedProperties.keys(); e.hasMoreElements();) {
String key = (String) e.nextElement();
String val = (String) properties.get(key);
if (!"?".equals(val)) {
// Property was removed or has a valid new value
tp.remove(key);
}
}
}
}
// Now update all selected Properties with the
// new data
for (Point point : propertiesCoordinates) {
Properties tp = getPropertiesAt(point);
if (tp == null) {
tp = new Properties();
setPropertiesAt(point, tp);
}
for (Enumeration<?> e = properties.keys(); e.hasMoreElements();) {
String key = (String) e.nextElement();
String val = properties.getProperty(key);
if (!"?".equals(val)) {
tp.setProperty(key, val);
}
}
}
}
@Override
public void tableChanged(TableModelEvent e) {
applyPropertiesToTiles();
}
}